Java 使用 Zookeeper 实现分布式锁
分布式锁设计思路
分布式锁有多种实现方式,比如通过数据库、redis 都可实现。作为分布式协同工具 ZooKeeper,当然也有着标准的实现方式。下面介绍在 Zookeeper 中如何实现排他锁。
- 每个客户端往
/Locks下创建临时有序节点/Locks/Lock_,创建成功后/Locks下面会有每个客户端对应的节点, 如/Locks/Lock_00000001 - 客户端取得
/Locks下子节点,并进行排序,判断排在最前面的是否为自己,如果自己的锁节点在第一位,代表获取锁成功 - 如果自己的锁节点不在第一位,则监听自己前一位的锁节点。例如,自己锁节点为
Lock_00000002,那么则监听Lock_00000001 - 当前一位锁节点
Lock_0000001对应的客户端执行完成,释放了锁,将会触发监听客户端Lock_00000002的逻辑 - 监听客户端重新执行第2步逻辑,判断自己是否获得了锁
基础连接
因为这个连接方式都大同小异,所以这里直接写在这里了,下面就不再重复这块代码
public class MyLock {
// zk连接对象
public static ZooKeeper zooKeeper;
// 计数器对象
private static CountDownLatch countDownLatch = new CountDownLatch(1);
// zk的连接串
private static String ip = "127.0.0.1:2181";
// 锁的节点名称
public static final String LOCK_ROOT_PATH = "/Locks";
public static final String LOCK_NODE_NAME = LOCK_ROOT_PATH + "/lock_";
private String lockPath;
private Watcher watcher = new Watcher() {
@Override
public void process(WatchedEvent event) {
if (event.getType() == Watcher.Event.EventType.NodeDeleted) {
synchronized (this) {
notifyAll();
}
}
}
};
/**
* 构造方法
*/
public MyLock() {
try {
// 打开zookeeper连接
zooKeeper = new ZooKeeper(ip, 5000, new Watcher() {
@Override
public void process(WatchedEvent event) {
if (event.getType() == Event.EventType.None) {
if (event.getState() == Event.KeeperState.SyncConnected) {
System.out.println("连接成功");
countDownLatch.countDown();
}
}
}
});
countDownLatch.await();
} catch (Exception e) {
e.printStackTrace();
}
}
}